package com.nexus.plugin.security.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.nexus.core.exception.AuthenicException;
import com.nexus.core.auth.LoginUser;
import com.nexus.core.utils.ObjectUtils;
import com.nexus.plugin.security.constants.AuthConstants;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;

/**
 * JWT生成token
 *
 * @Date 2025/7/30 15:11
 * @Author luzhengning
 **/
public class JwtTokenProvider extends JWT {

    /**
     * 生成JWT_token
     *
     * @Author: 路正宁
     * @Date: 2022/12/13 17:13
     */
    public static String createToken(LoginUser loginUser,int ExpireHour) throws AuthenicException {
        if (ObjectUtils.isEmpty(loginUser) || ObjectUtils.isEmpty(loginUser.getId()) || ObjectUtils.isEmpty(loginUser.getUsername()) || ObjectUtils.isEmpty(loginUser.getUser())) {
            throw new AuthenicException("用户登录信息错误");
        }

        HashMap<String, Object> map = new HashMap<>();
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.HOUR, ExpireHour); // 设置过期时间3600秒

        // 生成令牌
        String token = create().withHeader(map).withClaim("id", loginUser.getId()).withClaim("username", loginUser.getUsername())
                // 指定令牌的过期时间
                .withExpiresAt(instance.getTime())
                // 签名/密钥
                .sign(Algorithm.HMAC256(AuthConstants.JWT_SECRET));
        return token;
    }

    /**
     * 验证token是否有效
     *
     * @Author: 路正宁
     * @Date: 2022/12/13 17:17
     */
    public static DecodedJWT verify(String jwtToken) throws AuthenicException {
        if (ObjectUtils.isEmpty(jwtToken)) {
            throw new AuthenicException("token为空");
        }
        try {
            // 验证token
            DecodedJWT verify = require(Algorithm.HMAC256(AuthConstants.JWT_SECRET)).build().verify(jwtToken);
            return verify;
        } catch (AlgorithmMismatchException ex) {
            throw new AuthenicException("登录凭证算法不一致", 403);
        } catch (SignatureVerificationException ex) {
            throw new AuthenicException("无效签名", 403);
        } catch (TokenExpiredException ex) {
            throw new AuthenicException("登录凭证已过期", 403);
        } catch (InvalidClaimException ex) {
            throw new AuthenicException("登录凭证校验失败", 403);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new AuthenicException("登录凭证校验失败", 403);
        }

    }

    /**
     * 根据TOKEN获取登录用户
     *
     * @Date 2023/6/28 15:56
     * @Author luzhengning
     **/
    public static LoginUser getLoginUser(String jwtToken) throws AuthenicException {
        if (ObjectUtils.isEmpty(jwtToken)) {
            throw new AuthenicException("token为空");
        }
        DecodedJWT verify = verify(jwtToken);
        LoginUser user = new LoginUser();
        user.setId(verify.getClaim("id").asString());
        user.setUsername(verify.getClaim("username").asString());
        if (ObjectUtils.isEmpty(user.getId()) || ObjectUtils.isEmpty(user.getUsername())) {
            throw new AuthenicException("Token错误，找不到登录信息");
        }
        return user;
    }

    /**
     * 从请求中解析JWT令牌
     *
     * @Date 2025/7/31 16:30
     * @Author luzhengning
     **/
    public static String resolveToken(HttpServletRequest req) {
        String bearerToken = req.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    /**
     * 获取认证信息
     *
     * @Date 2025/8/1 15:38
     * @Author luzhengning
     **/
    public static Authentication getAuthentication(String token) throws AuthenicException {
        LoginUser loginUser = getLoginUser(token);
        Collection<? extends GrantedAuthority> authorities = loginUser.getAuthorities();
        // UserDetails userDetails = this.userDetailsService.loadUserByUsername(getUsername(token));
        return new UsernamePasswordAuthenticationToken(loginUser, null, authorities);
    }

    /**
     * 计算Token的到期时间
     *
     * @param loginDate 登录时间（生成Token的时间）
     * @return 到期时间（LocalDateTime）
     * @Date 2025/8/1 15:39
     * @Author luzhengning
     **/
    public static LocalDateTime calculateExpireTime(LocalDateTime loginDate,int EXPIRE_HOUR) {
        // 防御性判断：如果登录时间为null，使用当前时间作为基准
        if (loginDate == null) {
            loginDate = LocalDateTime.now();
        }
        // 在登录时间基础上增加有效期小时数
        return loginDate.plusHours(EXPIRE_HOUR);
    }

    /**
     * 检查Token是否已过期
     *
     * @param expireTime Token的到期时间
     * @return true：已过期；false：未过期
     * @Date 2025/8/1 15:39
     * @Author luzhengning
     **/
    public static boolean isExpired(LocalDateTime expireTime) {
        // 到期时间在当前时间之前，说明已过期
        return expireTime.isBefore(LocalDateTime.now());
    }
}
